#ifndef VECTORGRAPH_H_
#define VECTORGRAPH_H_

#include <memory.h>
#include <ext/hash_map>
namespace stdext
{
	using namespace __gnu_cxx;
}

#include <boost/pool/object_pool.hpp>
#include <boost/shared_ptr.hpp>

#include "graph_support/attributes/LengthEdgeAttributes.h"

#include "graph_support/impls/BaseGraphTmpl.h"
#include "graph_support/impls/vector/VertexWrap.h"
#include "graph_support/impls/Edge.h"
#include "graph_support/impls/WrapEdgeIterator.h"
#include "graph_support/impls/Wrap2VertIteratorAdapter.h"

#include "graph_support/utils/ResolveTableT.h"


namespace GRAPH_SUPPORT_NS
{
namespace impls
{
namespace vector
{

// TODO 9 [not sure] feature with vertices storage
template <
			typename VertexT = int,
			typename EdgeAttributesT = attributes::Length1EdgeAttributes,
			typename HashFn = stdext::hash< VertexT >,
			typename CmpFn = stdext::equal_to< VertexT >, // compares VertexT - s
			typename VertNumResolver = utils::ResolveTableHash< VertexT, size_t, HashFn, CmpFn >
			>
class VectorGraphTmpl : public BaseGraphTmpl< VertexWrap< VertexT, EdgeAttributesT >, HashFn, CmpFn, VertNumResolver >
{
	// TODO: too much public vs. private
private: // TODO: move down
	typedef BaseGraphTmpl< VertexWrap< VertexT, EdgeAttributesT >, HashFn, CmpFn, VertNumResolver > Super;
	typedef VectorGraphTmpl< VertexT, EdgeAttributesT, HashFn, CmpFn, VertNumResolver > MyT;
public:
	typedef VertexT GrVertex;
	typedef EdgeAttributesT EdgeAttributes;
private:
	typedef VertexWrap< GrVertex, EdgeAttributes > GrVertexWrap;
public:
	// TODO: all wrap-s
	typedef impls::Wrap2VertIteratorAdapter<
			typename std::vector< GrVertexWrap >::iterator,
			GrVertex
			> VertexIterator;
	typedef Edge< GrVertex, GrVertexWrap, EdgeAttributes > GrEdge;
	typedef GrEdge * GrEdgePtr;
	typedef typename GrVertexWrap::EdgeIterator EdgeIterator;
private:
	// TODO: macroses
	typedef typename IGraph::EdgeAttributesImpl< EdgeAttributes >::IAttributes IEdgeAttributes;
//	typedef typename IGraph::EdgeAttributesImpl< EdgeAttributes >::Attributes IEdgeAttributesImpl;

public:
	template< typename IterT >
	VectorGraphTmpl( IterT verticesBeg, IterT verticesEnd, bool isBidirected = false )
		: Super( verticesBeg, verticesEnd, isBidirected )
	{
	}

	template< typename CollT >
	VectorGraphTmpl( const CollT & vertsColl, bool isBidirected = false )
		: Super( vertsColl.begin(), vertsColl.end(), isBidirected )
	{
	}

// access
public:
	VertexIterator getVerticesBeg()
	{
		return VertexIterator( Super::vertices.begin() );
	}

	VertexIterator getVerticesEnd()
	{
		return VertexIterator( Super::vertices.end() );
	}

	EdgeIterator getEdgsBeg( const GrVertex & v )
	{
		size_t vid = Super::vert2numTable[v];
		return getEdgsBegId( vid );
	}

	EdgeIterator getEdgsEnd( const GrVertex & v )
	{
		size_t vid = Super::vert2numTable[v];
		return getEdgsEndId( vid );
	}

	EdgeIterator getEdgsBegId( size_t vid )
	{
		Super::checkVIDValid( vid );
		return Super::vertices[vid].getEdgesBeg();
	}

	EdgeIterator getEdgsEndId( size_t vid )
	{
		Super::checkVIDValid( vid );
		return Super::vertices[vid].getEdgesEnd();
	}

	template< typename FnT >
	void forEachOutEdge( GrVertex v, const FnT & fn )
	{
		forEachOutEdgeId( Super::vert2num( v ), fn );
	}

	template< typename FnT >
	void forEachOutEdgeId( size_t vid, const FnT & fn )
	{
		// TODO: common style of superclasses
		// TODO: use this for each where possible
		// TODO: proper implementation
		Super::checkVIDValid( vid );
		GrVertexWrap & w = Super::vertices[vid];
		std::for_each( w.getEdgesBeg(), w.getEdgesEnd(),
				boost::bind( fn, boost::bind( & utils::ptr2ref< GrEdge, GrEdgePtr >, _1 ) ) );
	}

	virtual IGraph::IEdgeIteratorPtr igetOutEdgesIterator( size_t vid )
	{
		return IGraph::IEdgeIteratorPtr( new WrapEdgeIterator< EdgeIterator, MyT >( * this, getEdgsBegId( vid ), getEdgsEndId( vid ) ) );
	}

	virtual void igetOutEdgesIterator( size_t vid, IGraph::IEdgeIterator & iter )
	{
		// TODO: typedef WrapEdgeIterator< EdgeIterator, MyT >
		WrapEdgeIterator< EdgeIterator, MyT > * iterptr = dynamic_cast< WrapEdgeIterator< EdgeIterator, MyT > * >( & iter );
		if ( iterptr == NULL )
		{
			throw GRAPH_SUPPORT_NS::exceptions::BadGraphItemException();
		}
		* iterptr = WrapEdgeIterator< EdgeIterator, MyT >( * this, getEdgsBegId( vid ), getEdgsEndId( vid ) );
	}

// modify
public:
	// TODO 9 [not sure and not critical and performance blocked] may be edit via wraps
	void addEdge( const GrVertex & beg, const GrVertex & end, const EdgeAttributes & edgeAttrs = EdgeAttributes() )
	{
		const size_t begVid = Super::vert2numTable[beg];
		const size_t endVid = Super::vert2numTable[end];

		GrEdgePtr edge = addSingleEdge( begVid, endVid, edgeAttrs );
		if ( Super::isBidirected )
		{
			GrEdgePtr redge = addSingleEdge( endVid, begVid, edgeAttrs );
			edge->getAttributes().onBidirEdgeCreated( redge->getAttributes(), true );
			redge->getAttributes().onBidirEdgeCreated( edge->getAttributes(), false );
		}
	}

	virtual void iaddEdge( size_t begVid, size_t endVid, const IGraph::IEdgeAttributesPtr & iattrs )
	{
		IEdgeAttributes * attrs = dynamic_cast< IEdgeAttributes * >( iattrs.get() );
		assert( attrs != NULL );
		GrVertex beg = Super::num2vert( begVid );
		GrVertex end = Super::num2vert( endVid );
		addEdge( beg, end, * attrs->get() );
	}

private:
	GrEdgePtr addSingleEdge( size_t begVid, size_t endVid, const EdgeAttributes & edgeAttrs )
	{
//		GrEdgePtr edge = edgesPool.construct( begVid, endVid, Super::vertices, edgeAttrs );
		// TODO: this is unsafe
		GrEdgePtr edge = new ( edgesPool.malloc() ) GrEdge( begVid, endVid, Super::vertices, edgeAttrs );
		Super::vertices[begVid].addEdge( edge );
		return edge;
	}

private:
	boost::object_pool< GrEdge > edgesPool;
	// TODO: move 2 base class
};

}
}
}

#endif /* VECTORGRAPH_H_ */
